#ifndef _THREAD_H_
#define _THREAD_H_

#include <process.h>

// define the thread function for class.
class tThreadCtrl
{
#ifndef _linux_
	HANDLE hStopEvent;		// Event that notify that the thread is stopped.
#else
	//tSemaphore Sema;
#endif

protected:
#ifndef _linux_
	static void StaticThreadProc(void *param);
#else
	static void* StaticThreadProc(void *param);
#endif

#ifndef _linux_
	HANDLE hThread;			// thread handle.
#else
	pthread_t ThreadID;
#endif

public:
	//---------------------------------------------------------------
	// start a instance thread. It will create a thread with 
	// StaticThreadProc(void* param) function.
	//---------------------------------------------------------------
	void StartThread();
	//---------------------------------------------------------------
	
	//---------------------------------------------------------------
	// Thread carrying function. It will call the ThreadProc() which is
	// implemented by child class and has real process.
	//---------------------------------------------------------------

	//---------------------------------------------------------------

	//---------------------------------------------------------------
	// Set Stop event, to notify the thread is stopped. This function 
	// can only be called by StaticThreadProc(), any other thread and 
	// instance must not call this function.
	//---------------------------------------------------------------
	void SetThreadStop();
	//---------------------------------------------------------------

	//---------------------------------------------------------------
	// Wait for thread stopped. Called by child class.
	//---------------------------------------------------------------
	void Wait();
	//---------------------------------------------------------------

	//---------------------------------------------------------------
	// Real function for thread proc. implemented by child class.
	//---------------------------------------------------------------
	virtual void ThreadProc() = 0;
	//---------------------------------------------------------------

public:
	tThreadCtrl();
	~tThreadCtrl();
};

inline tThreadCtrl::tThreadCtrl()
{
#ifndef _linux_
	hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	hThread = 0;
#else
	ThreadID = 0;
#endif
}

inline tThreadCtrl::~tThreadCtrl()
{
	Wait();
#ifndef _linux_
	CloseHandle(hStopEvent);
#else
	// Do nothing.
#endif
}

inline void tThreadCtrl::StartThread()
{
#ifndef _linux_
	if (hThread == 0)
		hThread = (HANDLE)_beginthread(StaticThreadProc, 0, this);
#else
	if (ThreadID == 0)
	{
		int r = pthread_create(&ThreadID, NULL,
							   StaticThreadProc, this);
		assert(r == 0);
	}
#endif
}
	
#ifndef _linux_
inline void tThreadCtrl::StaticThreadProc(void *param)
#else
inline void * tThreadCtrl::StaticThreadProc(void *param)
#endif
{
	tThreadCtrl* p = (tThreadCtrl*)param;
	ResetEvent(p->hStopEvent);
	p->ThreadProc();
	p->SetThreadStop();
}

inline void tThreadCtrl::SetThreadStop()
{
	hThread = NULL;
#ifndef _linux_
	SetEvent(hStopEvent);
#else
	//Sema.Post();
#endif
}

inline void tThreadCtrl::Wait()
{
#ifndef _linux_
	if (hThread != 0)
	{
		WaitForSingleObject(hStopEvent, INFINITE);
		hThread = 0;
	}
#else
	if (ThreadID != 0)
	{
		pthread_join(ThreadID, NULL);
	}
#endif
}

#endif
